#include "Base.h"
#include "Files.h"
#include <fstream>
#include <sstream>
#include <Windows.h>
#include <stdio.h>
#include <direct.h>
#include <conio.h>


void Configs::ValidateConfig(string fName){

	fName.insert(0, "Configs\\");
	char dir[MAX_PATH];
	DWORD dwRet;
	dwRet = GetCurrentDirectory(MAX_PATH, dir);
	string path(dir + fName);
	ofstream nFile;
	FileBuffer file(fName);

	if (!file.Exists()){
		nFile.open(file.GetDir().c_str());
		if (!nFile){
			Engine::ThrowError("Unable to create config file. Check write permissions?");
		}
		nFile.close();
	
		// if it still doesn't exist. try and create the folder then the file again
		if (!file.Exists()){

			string folder(dir);
			#if _DEBUG
				folder.append("\\Build\\Configs\\");
			#else
				folder.append("\\Configs\\");
			#endif // DEBUG
			mkdir(folder.c_str());

			nFile.open(file.GetDir().c_str());
			if (!nFile){
				Engine::ThrowError("Unable to create config file. Check write permissions?");
			}
			nFile.close();

			// double check if it's there, if not, give up
			if (!file.Exists()){
				Engine::ThrowError("Unable to create config file. Check write permissions?");
			}
		}
	}
}

list<string> Configs::GetConfig(string fName){
	ValidateConfig(fName);
	string subfolders;
	fName.insert(0, "Configs\\");
	FileBuffer file(fName);
	if (!file.Exists()){
		Engine::ThrowError("Unable to read config file. Check write permissions?");
	}

	return file.ReadLines();
}

void Configs::SetConfig(string fName, string data){
	ValidateConfig(fName);

	fName.insert(0, "Configs\\");
	FileBuffer file(fName);
	if (!file.Exists()){
		Engine::ThrowError("Unable to write to config file. Check write permissions?");
	}

	file.Replace(data);
}

void Configs::ReplaceConfig(string fName, string data){
	ValidateConfig(fName);
	
	fName.insert(0, "Configs\\");
	FileBuffer file(fName);
	if (!file.Exists()){
		Engine::ThrowError("Unable to write to config file. Check write permissions?");
	}

	file.Replace(data);
}

FileBuffer::FileBuffer(string fileName){
	char dir[MAX_PATH];
	DWORD dwRet;
	dwRet = GetCurrentDirectory(MAX_PATH, dir);
	#if _DEBUG
		fileName.insert(0, "\\Build\\");
	#else
		fileName.insert(0, "\\");
	#endif // DEBUG
	path = string(dir + fileName);
}

bool FileBuffer::Exists(){
	DWORD dwAttrib = GetFileAttributes(path.c_str());

	return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
	!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}

void FileBuffer::SetDir(string nDir){
	char dir[MAX_PATH];
	DWORD dwRet;
	dwRet = GetCurrentDirectory(MAX_PATH, dir);
	#if _DEBUG
		nDir.insert(0, "\\Build\\");
	#else
		nDir.insert(0, "\\");
	#endif // DEBUG
	path = string(dir + nDir);
}

string FileBuffer::GetDir(){
	return path;
}

bool FileBuffer::Create(){
	if (!Exists()){
		ofstream nFile;
		nFile.open(path);
		if (!nFile){
			Engine::ThrowError("Cannot create file: " + path);
		}
		nFile.close();

		if (!Exists()){
			return false;
		}else{
			return true;
		}
	}
	return true;
}

string FileBuffer::Read(){
	ifstream f;
	f.open(path);
	if (!f){
		Engine::ThrowError("Cannot read file: " + path);
	}
	if (!f.good()){
		Engine::ThrowError("Cannot read file: " + path);
	}
	string line;
	string data;
	if (f.is_open()){
		while (getline(f, line)){
			data.append(line + "\n");
		}
		f.close();
	}
	return data;
}

list<string> FileBuffer::ReadLines(){
	string line;
	list<string> lines;
	ifstream f;
	f.open(path);
	if (!f){
		Engine::ThrowError("Cannot read file: " + path);
	}
	if (!f.good()){
		Engine::ThrowError("Cannot read file: " + path);
	}
	if (f.is_open()){
		while (getline(f, line)){
			lines.push_back(line);
		}
		f.close();
	}
	return lines;
}

bool FileBuffer::Replace(string data){
	if (!Exists()){
		if (!Create()){
			return false;
		}
	}
	ofstream f(path, ios::out);
	if (!f){
		return false;
	}
	if (f.is_open()){
		char* buffer = new char[data.size() + 1];
		buffer[data.size()] = 0;
		memcpy(buffer, data.c_str(), data.size());
		f.flush();
		f.write(buffer, data.size());
		f.close();
	}
	return true;
}

bool FileBuffer::Append(string data){
	if (!Exists()){
		if (!Create()){
			return false;
		}
	}
	ofstream f;
	f.open(path, fstream::app);
	if(!f){
		return false;
	}
	if (f.is_open()){
		f << data;
		f.close();
	}else{
		return false;
	}
	return true;
}

bool FileBuffer::Delete(){
	if (Exists()){
		if (remove(path.c_str()) != 0){
			return false;
		}
	}
	return true;
}